﻿#region Creditos

/* Autor: Edilberto Sánchez Forero	*/
/* Email: esanchezfo@gmail.com		*/
/* Licencia: LGPL, Software Libre	*/
/* País: Colombia, Bogotá			*/

#endregion

#region Librerias

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Data.Linq;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Xml;

#endregion


namespace ESF.General
{
	public static class FileHelper
	{
		#region Enumeraciones

		public enum FileSort
		{
			None,
			Filename_ASC,
			Filename_DESC,
			DateTimeCreation_ASC,
			DateTimeCreation_DESC
		}

		#endregion


		#region Manejo de Carpetas

		public static void Delete (params string [] pFilenames)
		{
			foreach (string item in pFilenames)
			{
				Delete (item);
			}
		}

		
		public static bool Delete (string pFilename)
		{
			if (string.IsNullOrEmpty (pFilename)) { return false; }
						
			if (Directory.Exists (pFilename))
			{
				DeleteDirectory (pFilename);
			}
			else if (File.Exists(pFilename))
			{
				WaitFileLocked (pFilename);

				if (!pFilename.StartsWith (@"\\"))
				{
					File.SetAttributes(pFilename, FileAttributes.Normal);
				}

				File.Delete (pFilename);

				return true;
			}

			return false;
		}


		public static void Copy (string pFilenameOrigin, string pFileNameDestination)
		{
			FileInfo origin, destination;


			if (string.IsNullOrWhiteSpace (pFilenameOrigin) || string.IsNullOrWhiteSpace (pFileNameDestination)) { return; }

			
			EnsureFolder(pFileNameDestination); 
					
			if (!File.Exists(pFilenameOrigin))
			{
				return;
			}

			if (!pFilenameOrigin.StartsWith(@"\\"))
			{
				File.SetAttributes(pFilenameOrigin, FileAttributes.Normal);
			}
					
			origin = new FileInfo (pFilenameOrigin);

			destination = new FileInfo (pFileNameDestination);

			// Si son iguales
			if (EqualsOfLengthWrite (origin, destination))
			{
				return;
			}
					
			Delete(pFileNameDestination); 

			File.Copy (pFilenameOrigin, pFileNameDestination);
		}


		public static void Move (string pFilenameOrigin, string pFileNameDestination)
		{
			Copy (pFilenameOrigin, pFileNameDestination);

			Delete (pFilenameOrigin);
		}


		public static DirectoryInfo EnsureFolder_yyyyMM (string pstrFolderPath)
		{
			return EnsureFolderWithDateFormat (pstrFolderPath, "yyyy-MM");
		}


		public static DirectoryInfo EnsureFolder_yyyyMMdd (string pstrFolderPath)
		{
			return EnsureFolderWithDateFormat (pstrFolderPath, "yyyy-MM-dd");
		}


		public static DirectoryInfo EnsureFolderWithDateFormat (string pstrFolderPath, string pDateFormat)
		{
			 return EnsureFolder (Path.Combine (pstrFolderPath, DateTime.Now.ToString (pDateFormat)));
		}


		public static DirectoryInfo EnsureFolder (string pstrFolderPath)
		{
			string [] pRelativeFolders;
			string currentPath = string.Empty;


			// si es un archivo se le saca el directorio
			if (!string.IsNullOrWhiteSpace (Path.GetExtension (pstrFolderPath)))
			{
				pstrFolderPath = Path.GetDirectoryName (pstrFolderPath);
			}
			
			
			// Se quita el separador del final para que no lo incluya al obtener las carpetas
			if (pstrFolderPath.EndsWith (Path.DirectorySeparatorChar.ToString ()))
			{
				pstrFolderPath = pstrFolderPath.Substring (0, pstrFolderPath.Length - 1);
			}


			try
			{
				// No es una carpeta compartida (local)
				if (!pstrFolderPath.StartsWith (@"\\"))
				{					
					// Se parte la ruta por los separadores de carpeta para luego validar que toda la ruta existe desde su raiz
					pRelativeFolders = pstrFolderPath.Split (Path.DirectorySeparatorChar);
				
					foreach (string pathPart in pRelativeFolders)
					{
						currentPath += pathPart + Path.DirectorySeparatorChar;

						if (!Directory.Exists(currentPath))
						{
							Directory.CreateDirectory (currentPath);
						}
					}

					return new DirectoryInfo(pstrFolderPath);
				}
				else
				{
					return Directory.CreateDirectory(pstrFolderPath);
				}
			}
			catch (Exception excEx)
			{
				throw new GenericException (GenericException.CRI_FOLDER_ERROR, 
					string.Format ("No fue creado el directorio {0}, {1}", pstrFolderPath, excEx.Message), excEx);
			}
		}
		
		
		public static void DeleteDirectory (string pstrFolderPath)
		{
			if (string.IsNullOrEmpty (pstrFolderPath)) { return; }

			if (Directory.Exists (pstrFolderPath))
			{
				ProcessHelper.ReTryWhen (() =>
				{
					ExecuteInDirectoryFiles (pstrFolderPath, 
					delegate (string pFilePath, object [] pParams)
					{
						Delete (pFilePath);
					});

					ExecuteInDirectory (pstrFolderPath,  
					delegate (string pDir, string [] pParams)
					{
						Directory.Delete (pDir);
					});
				}, 
				delegate (Exception pEx, int pTryCount)
				{
					if (pTryCount > 20)
					{
						return false;
					}

					return true;
				});
			}
		}

		#endregion


		#region ExecuteInFiles

		#region ListDirectory

		public static int GetDirectoryCount (string pFolderPath, int pMaxDepth = -1, Func<string, bool> pWhere = null)
		{
			return ListDirectories (pFolderPath, pMaxDepth, pWhere).Count ();
		}


		public static IEnumerable<string> ListDirectories(string pFolderPath, int pMaxDepth = -1, Func<string, bool> pWhere = null)
		{
			if (pMaxDepth > 0)
			{
				if (FileHelper.SplitWithoutUnitLabel(pFolderPath).Length > pMaxDepth)
				{
					yield break;
				}
			}

			foreach (string dir in Directory.EnumerateDirectories(pFolderPath, "*", SearchOption.TopDirectoryOnly))
			{
				if (pWhere != null)
				{
					if (pWhere(dir))
					{
						yield return dir;
					}
				}
				else
				{
					yield return dir;
				}

				foreach (string dirx in ListDirectories (dir,  pMaxDepth, pWhere))
				{
					yield return dirx;
				}
			}
		}
		
		#endregion


		#region ListFiles

		public static bool ExistsDirectory (string pDirectoryPath)
		{
			// Es UNC se trata de leer sus contenidos por error no existe si lee algo existe
			if (pDirectoryPath.StartsWith (@"\\"))
			{
				try
				{
					return (DateTime.Compare (new DirectoryInfo (pDirectoryPath).LastWriteTime, DateTime.MinValue) > 0);
				}
				catch (Exception pEx)
				{
					Log.Error (pEx);

					return false;
				}
			}

			return Directory.Exists (pDirectoryPath);
		}

		
		public static IEnumerable<FileInfo> ListFileInfos (string pFolderPath, string [] pFileExtensions = null, SearchOption pSearchOption = SearchOption.AllDirectories)
		{
			foreach (string filePath in ListFiles (pFolderPath, pFileExtensions, pSearchOption))
			{
				yield return new FileInfo (filePath);
			}
		}
		
				
		public static IEnumerable<string> ListFiles (string pFolderPath, string [] pFileExtensions = null, SearchOption pSearchOption = SearchOption.AllDirectories)
		{
			if (!ExistsDirectory (pFolderPath))
			{
				yield break;
			}
			

			if (DataHelper.IsEmpty (pFileExtensions))
			{
				foreach (string filePath in Directory.EnumerateFiles(pFolderPath, "*.*", pSearchOption))
				{
					yield return filePath;
				}

				yield break;
			}
			

			foreach (string filePath in Directory.EnumerateFiles (pFolderPath, "*.*", pSearchOption))
			{
				if (TextHelper.IsIn (Path.GetExtension (filePath), pFileExtensions))
				{
					yield return filePath;
				}
			}
		}


		public static string RemoveFinalSeparator(string pFolderPath)
		{
			if (pFolderPath.EndsWith(Path.DirectorySeparatorChar.ToString()))
			{
				return pFolderPath.Substring(0, pFolderPath.Length - 1);
			}

			return pFolderPath;
		}


		public static string [] SplitWithoutUnitLabel (string pFolderPath)
		{
			pFolderPath = RemoveFinalSeparator (pFolderPath);

			if (pFolderPath.StartsWith (@"\\"))
			{
				pFolderPath = pFolderPath.Substring (2);
				pFolderPath = pFolderPath.Substring (pFolderPath.IndexOf (Path.DirectorySeparatorChar) + 1);
			}

			if (pFolderPath.IndexOf(':') != -1)
			{
				pFolderPath = pFolderPath.Substring (pFolderPath.IndexOf (':') + 2);
			}
			
			return pFolderPath.Split (Path.DirectorySeparatorChar);
		}

		#endregion


		public static int ExecuteInDirectoryFiles(string pFolderPath, Action<FileInfo, object[]> pDelegate, object[] pParams = null, string[] pFileExtensions = null, CancellationTokenSource pCTS = null, SearchOption pSearchOption = SearchOption.AllDirectories)
		{
			return ExecuteInDirectoryFiles (pFolderPath, 
				(string pFileName, object [] ppParams) => { pDelegate (new FileInfo (pFileName), ppParams); }, pParams, pFileExtensions, pCTS, pSearchOption);
		}


		public static int ExecuteInDirectoryFiles(string pFolderPath, Action<string, object[]> pDelegate, object[] pParams = null, string[] pFileExtensions = null, CancellationTokenSource pCTS = null, SearchOption pSearchOption = SearchOption.AllDirectories)
		{
		    int totalFileCount = 0;


			Parallel.ForEach<string> (
				ListFiles (pFolderPath, pFileExtensions, pSearchOption),
				ProcessHelper.GetDefaultParallelOptions (pCTS),
				delegate (string pFilePath)
				{
					Interlocked.Increment (ref totalFileCount);

					pDelegate (pFilePath, pParams);
				});

			return totalFileCount;
		}


		public static List<FileInfo> SearchFileLIKEFileName(string pFolderPath, string pSearchTerm)
		{
			return SearchFileWhere(pFolderPath, 
				delegate(FileInfo pFileInfo) 
				{
					return pFileInfo.FullName.Contains(pSearchTerm); 
				});
		}


		public static List<FileInfo> SearchFileWhere(string pFolderPath, Func<FileInfo, bool> pWhere)
		{
			List<FileInfo> result = new List<FileInfo> ();

			
			ExecuteInDirectoryFiles (pFolderPath, 
				delegate (FileInfo pFileInfo, object [] pParams) 
				{  
					if (pWhere (pFileInfo))
					{
						result.Add (pFileInfo);
					}
				});

			return result;
		}

		#endregion


		#region ExecuteInDirectory

		#region FileCount

		public static int GetFileCount (string pFolderPath, string [] pFileExtensions = null, SearchOption pSearchOption = SearchOption.AllDirectories)
		{
			int fileCount = 0;

			ExecuteInDirectoryFiles (pFolderPath,  
				(string pFilePath, object [] pParams) => 
				{
					Interlocked.Increment (ref fileCount);
				},
				pFileExtensions,
				pSearchOption: pSearchOption
			);

			return fileCount;
		}

		#endregion

		public static void ExecuteInDirectory(string pFolderPath, Action<DirectoryInfo, string[]> pDelegate, string[] pFileExtensions = null, SearchOption pSearchOption = SearchOption.AllDirectories, CancellationTokenSource pCTS = null)
		{
			ExecuteInDirectory (
				pFolderPath,
				(string pDirPath, string [] pFileExtensionsx) => { pDelegate(new DirectoryInfo(pDirPath), pFileExtensionsx); },
				pFileExtensions, 
				pSearchOption, pCTS);
		}


		public static void ExecuteInDirectory(string pFolderPath, Action<string, string[]> pDelegate, string[] pFileExtensions = null, SearchOption pSearchOption = SearchOption.AllDirectories, CancellationTokenSource pCTS = null)
		{
			Parallel.ForEach<string> (Directory.EnumerateDirectories (pFolderPath, "*", pSearchOption), 
				ProcessHelper.GetDefaultParallelOptions (pCTS),
				(string pDir) =>
				{
					pDelegate (pDir, pFileExtensions);
				});
		}
		
		#endregion
		
		
		#region Creacion de Archivos
		
		public static TextWriter CreateText (string pFilename)
		{
			string directory;
			
		
			// Garantiza que este el directorio
			directory = Path.GetDirectoryName (pFilename);
			
			if (!string.IsNullOrEmpty (directory))
			{
				EnsureFolder (directory);
			}
			
			return File.CreateText (pFilename);
		}
		
		#endregion
		
		
		#region Funciones de Ajuste
		
		public static string GenerateTempFileName (string pExtension = ".tmp")
		{
			return GenerateTempFileName (ReadConfig.TempDirectory, string.Empty, pExtension);
		}


		public static string GenerateTempFileName (string pSubFolder, string pExtension = ".tmp")
		{
			return GenerateTempFileName (ReadConfig.TempDirectory, pSubFolder, pExtension);
		}


		public static string GenerateTempFileName (string pTempFolder, string pSubFolder, string pExtension = ".tmp")
		{
			string result;


			result = Path.Combine (pTempFolder, pSubFolder, Guid.NewGuid ().ToString () + pExtension);

			EnsureFolder (result);

			return result;
		}


		public static string AddFinalSeparator (string pstrFolderPath)
		{
			if (string.IsNullOrEmpty (pstrFolderPath)) { return null; }
		
			if (pstrFolderPath.EndsWith (Path.DirectorySeparatorChar.ToString ())) { return pstrFolderPath; }
			
			return pstrFolderPath + Path.DirectorySeparatorChar;
		}


		public static string AddSufix (string pFilename, string pSufix)
		{
			return (pFilename.Substring (0, pFilename.LastIndexOf ('.')) + pSufix + Path.GetExtension (pFilename));
		}


		public static string ReplaceFullPathExtension (string pFilename, string pSufix, string pReplaceExtension)
		{
			return ReplaceFullPathExtension (AddSufix (pFilename, pSufix), pReplaceExtension);
		}


		public static string ReplaceFullPathExtension (string pFilename, string pReplaceExtension)
		{
			return Path.GetDirectoryName (pFilename) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension (pFilename) + pReplaceExtension;
		}
		
		#endregion
		

		#region Comparacion

		public static bool EqualsOfLengthWrite (FileInfo pA, FileInfo pB)
		{
			if (!pA.Exists)
			{
				return false;
			}

			if (!pB.Exists)
			{
				return false;
			}

			if (pA.Length == pB.Length
				&& Math.Abs (((TimeSpan) (pA.LastWriteTime - pB.LastWriteTime)).TotalMilliseconds) < 200)
			{
				return true;
			}

			return false;
		}

		#endregion

		
		#region Funciones para Busqueda de Archivos
		
		public static List<FileInfo> GetFilesByNameLeftPart (string pDirectoryPath, string pLeftPartName)
		{
			List<FileInfo> fileInfos;
			
			
			fileInfos = new List<FileInfo> ();
			
			foreach (FileInfo fi in new DirectoryInfo (pDirectoryPath).GetFiles ())
			{
				if (fi.Name.StartsWith (pLeftPartName))
				{
					fileInfos.Add (fi);
				}
			}
			
			return fileInfos;
		}
				
		
		public static List<FileInfo> GetFilesByExtension(string pFolderPath, string [] pFileExtensions = null, SearchOption pSearchOption = SearchOption.AllDirectories, FileSort pFileSort = FileSort.None)
		{
			List<FileInfo> result;


			result = ListFileInfos (pFolderPath, pFileExtensions, pSearchOption).ToList ();
			
			if (pFileSort != FileSort.None)
			{
				result.Sort (delegate (FileInfo pA, FileInfo pB) 
				{ 
					switch (pFileSort)
					{
						case FileSort.Filename_ASC:
							return Comparer<string>.Default.Compare (pA.Name, pB.Name);

						case FileSort.Filename_DESC:
							return -1 * Comparer<string>.Default.Compare (pA.Name, pB.Name);

						case FileSort.DateTimeCreation_ASC:
							return Comparer<DateTime>.Default.Compare (pA.CreationTime, pB.CreationTime);
						
						case FileSort.DateTimeCreation_DESC:
							return -1 * Comparer<DateTime>.Default.Compare (pA.CreationTime, pB.CreationTime);

						default: 
							return 0;
					}
				});
			}

			return result;
		}
		
		
		public static void DeleteFilesByNameLeftPart (string pDirectoryPath, string pLeftPartName)
		{
			foreach (FileInfo fi in GetFilesByNameLeftPart (pDirectoryPath, pLeftPartName))
			{
				fi.Delete ();
			}
		}
		
		
		public static void DeleteFilesByExtension (string pDirectoryPath, string [] pFileExtensions, SearchOption pSearchOption = SearchOption.AllDirectories)
		{
			foreach (string filePath in ListFiles (pDirectoryPath, pFileExtensions, pSearchOption))
			{
				FileHelper.Delete (filePath);
			}
		}
		
		
		public static void DeleteFilesByExtensionExceptOne (string pDirectoryPath, string pExcludedFilename, string [] pFileExtensions, SearchOption pSearchOption = SearchOption.AllDirectories)
		{
			foreach (string filePath in ListFiles (pDirectoryPath, pFileExtensions, pSearchOption))
			{
				if (Path.GetFileNameWithoutExtension (filePath) != pExcludedFilename)
				{
					FileHelper.Delete (filePath);
				}
			}
		}
		
		
		public static void DeleteFilesExceptOne (string pDirectoryPath, string pExcludedFilename)
		{
			foreach (FileInfo fi in new DirectoryInfo (pDirectoryPath).GetFiles ())
			{
				if (fi.Name != pExcludedFilename)
				{
					fi.Delete ();
				}
			}
		}
		

		public static void DeleteOldFiles (string pDirectoryPath, DateTime pOldestDateTime)
		{
			ExecuteInDirectoryFiles (pDirectoryPath,
				(FileInfo pFile, object [] pParams) => 
				{
					// Ej: junio 8 de 2012 :  10:00:00 - junio 7 de 2012 : 10:00:00
					// Ej: junio 8 de 2012 :  10:00:00 - junio 8 de 2012 : 10:00:00
					// Ej: junio 8 de 2012 :  10:00:00 - junio 9 de 2012 : 10:00:00
					// la fecha de corte es superior a la fecha de escritura se elimina
					if (DateTime.Compare (pOldestDateTime, pFile.LastWriteTime) > 0)
					{
						FileHelper.Delete (pFile.FullName);
					}
				});
		}


		public static bool IsDirectoryOverMaxSize (string pDirectoryPath, long pMaxSizeMegas)
		{
			return (((GetDirectoryTotalSize (pDirectoryPath) / 1024.0) / 1024.0) > pMaxSizeMegas);
		}


		public static long GetDirectoryTotalSize (string pDirectoryPath)
		{
			DirectoryInfo dir;

			long totalDirFilesLength;


			if (!Directory.Exists (pDirectoryPath)) { return 0; }

			totalDirFilesLength= 0;
			
			dir = new DirectoryInfo (pDirectoryPath);

			foreach (FileInfo file in dir.GetFiles ())
			{
				totalDirFilesLength += file.Length;
			}

			foreach (DirectoryInfo directory in dir.GetDirectories ())
			{
				totalDirFilesLength += GetDirectoryTotalSize (directory.FullName);
			}
			
			return totalDirFilesLength;
		}

		#endregion
		

		#region Listados

		public static string ExportXMLDirectoryFiles(string pDirectoryPath, string pResultXmlFileName = "", SearchOption pSearchOption = SearchOption.AllDirectories)
		{
			if (string.IsNullOrEmpty (pResultXmlFileName))
			{
				pResultXmlFileName = Path.Combine(Path.GetDirectoryName(pDirectoryPath), "directoryList.xml");
			}
			
			FileHelper.Delete(pResultXmlFileName);

			XmlWriter writer = XmlTextWriter.Create(pResultXmlFileName, new XmlWriterSettings() { Indent = true });

			writer.WriteStartElement ("Files");

			foreach (FileInfo item in ListFileInfos(pDirectoryPath))
			{
				writer.WriteStartElement ("File");

				writer.WriteAttributeString ("directoryName", item.DirectoryName);
				writer.WriteAttributeString ("name", item.Name);
				writer.WriteAttributeString ("creationDateTime", item.CreationTime.ToString(TextHelper.DEFAULT_DATETIME_LONGFORMAT));
				writer.WriteAttributeString ("lastModifiedDateTime", item.LastWriteTime.ToString (TextHelper.DEFAULT_DATETIME_LONGFORMAT));

				writer.WriteEndElement();
			}

			writer.WriteEndElement ();

			writer.Close ();


			return pResultXmlFileName;
		}

		#endregion

		
		#region Read
		
		public static bool IsFileLocked (IOException exception)
		{
			int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1);
			return errorCode == 32 || errorCode == 33;
		}


		public static FileStream GetFileStream(string pFileName)
		{
			return GetFileStream (pFileName, 10);
		}


		public static FileStream GetFileStream(string pFileName, int pTries)
		{
			return GetFileStream (pFileName, pTries, 1200);
		}


		public static FileStream GetFileStream(string pFileName, int pTries, int pTrySpleepMs)
		{
			var tries = 0;

			while (true)
			{
				try
				{
					return File.Open(pFileName, FileMode.Open, FileAccess.Read, FileShare.Read); 
				}
				catch (IOException e)
				{
					if (!IsFileLocked(e))
					{
						throw e;
					}
					if (++tries > pTries)
					{
						throw e;
					}

					Thread.Sleep (pTrySpleepMs);
				}
			}
		}


		public static FileInfo GetFileInfo (string pFilename)
		{
			if (File.Exists (pFilename))
			{
				return new FileInfo (pFilename);
			}

			return null;
		}

		public static byte[] ReadFile (string filePath)
		{
			byte[] buffer;
			
			FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
			
			
			try
			{
				int length = (int)fileStream.Length;  // get file length
				buffer = new byte[length];            // create buffer
				int count;                            // actual number of bytes read
				int sum = 0;                          // total number of bytes read

				// read until Read method returns 0 (end of the stream has been reached)
				while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
					sum += count;  // sum is a buffer offset for next reading
			}
			finally
			{
				fileStream.Close();
			}
			
			return buffer;
		}
		
		#endregion


		#region Watcher

		public static bool IsFileLocked (FileInfo pFile)
		{
			return IsFileLocked (pFile.FullName);
		}


		public static bool IsFileLocked(string pFileName)
		{
			FileStream stream = null;


			if (!File.Exists (pFileName))
			{
				return false;
			}

			try
			{
				stream = new FileStream (pFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
			}
			catch (IOException)
			{
				//the file is unavailable because it is:
				//still being written to
				//or being processed by another thread
				//or does not exist (has already been processed)
				return true;
			}
			finally
			{
				if (stream != null)
					stream.Close();
			}

			//file is not locked
			return false;
		}


		public static void WaitFileLocked (FileInfo pFile)
		{
			WaitFileLocked (pFile.FullName);
		}


		public static void WaitFileLocked (string pFileName)
		{
			while (IsFileLocked(pFileName))
			{
				Thread.Sleep(500);
			}
		}


		public static void RefreshFSWatchers (List<FileSystemWatcher> pWatchers, FileSystemEventHandler pChangedHandler, FileSystemEventHandler pCreatedHandler, FileSystemEventHandler pDeletedHandler, params string [] pDirectoryPaths)
		{
			List<string> directoryPaths = null;
			

			if (pWatchers == null)
			{
				pWatchers = new List<FileSystemWatcher> ();
			}

			// Si no hay directorios para monitorear se detienen los watchers
			if (DataHelper.IsEmpty (pDirectoryPaths))
			{
				foreach (FileSystemWatcher w in pWatchers)
				{
					w.EnableRaisingEvents = false;
				}

				pWatchers.RemoveAll (fsw => !fsw.EnableRaisingEvents);

				return;
			}

			// Para cada directorio sin monitorear se adicionar el watcher
			foreach (string monDirPath in 
				directoryPaths.
					FindAll (md => Directory.Exists (md) 
						&& !pWatchers.Exists (fsw => String.Compare (fsw.Path, md, true) == 0)))
			{
				pWatchers.Add (GenerateFSW (monDirPath, pChangedHandler, pCreatedHandler));
			}

			directoryPaths = new List<string> (pDirectoryPaths);

			foreach (FileSystemWatcher fsw in 
				pWatchers.FindAll (fw => !Directory.Exists (fw.Path)	
					|| !directoryPaths.Exists (dp => String.Compare (dp, fw.Path, true) == 0)))
			{
				fsw.EnableRaisingEvents = false;
			}
			
			pWatchers.RemoveAll (fsw => !fsw.EnableRaisingEvents);
		}


		public static FileSystemWatcher GenerateFSW (string pPath, FileSystemEventHandler pChangedHandler, FileSystemEventHandler pCreatedHandler)
		{
			FileSystemWatcher fsw;
			

			fsw = new FileSystemWatcher (pPath);

			fsw.Filter = "*.*";
			fsw.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastWrite;

			fsw.IncludeSubdirectories = true;

			fsw.Changed += pChangedHandler;
			fsw.Created += pCreatedHandler;

			fsw.Error += new ErrorEventHandler(delegate (object sender, ErrorEventArgs e) { Log.Error (e.GetException ()); });

			return fsw;
		}

		#endregion


		#region Nombres

		public static string GetFileNameFirstPoint (string pFileName)
		{
			int indexPoint;
			
			string copy;


			copy = Path.GetFileName (pFileName);

			indexPoint = copy.IndexOf('.');

			if (indexPoint == -1)
			{
				return copy;
			}

			return copy.Substring(0, indexPoint);
		}


		public static string GetFileNameExtensionFromFirstPoint(string pFileName)
		{
			int indexPoint;


			indexPoint = pFileName.IndexOf('.');

			if (indexPoint == -1)
			{
				return pFileName;
			}

			return pFileName.Substring (indexPoint);
		}

		#endregion
	}
}